// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef __C_OPENGL_PARALLAX_MAP_RENDERER_H_INCLUDED__
#define __C_OPENGL_PARALLAX_MAP_RENDERER_H_INCLUDED__

#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_OPENGL_

#include "COpenGLShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"

#include "IVideoDriver.h"
#include "matrix4.h"
#include "SLight.h"
#include "IMaterialRendererServices.h"

namespace irr
{
namespace video
{

#ifdef DELPHI_WRAP
	class COpenGLParallaxMapRendererCallBack : public IShaderConstantSetCallBack
	{
	private:
		f32 & DestCurrentScale;
	public:
		COpenGLParallaxMapRendererCallBack(f32 & DestScale) : DestCurrentScale(DestScale)
		{

		}
	public:
		virtual void _STDCALL_ OnSetMaterial(const SMaterial& material) { }
		virtual void _STDCALL_ OnSetConstants(IMaterialRendererServices* services, s32 userData)
		{
			IVideoDriver* driver = services->getVideoDriver();

			// set transposed world matrix
			const core::matrix4& tWorld = driver->getTransform(video::ETS_WORLD).getTransposed();
			services->setVertexShaderConstant(tWorld.pointer(), 0, 4);

			// set transposed worldViewProj matrix
			core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
			worldViewProj *= driver->getTransform(video::ETS_VIEW);
			worldViewProj *= driver->getTransform(video::ETS_WORLD);
			core::matrix4 tr(worldViewProj.getTransposed());
			services->setVertexShaderConstant(tr.pointer(), 8, 4);

			// here we fetch the fixed function lights from the driver
			// and set them as constants

			u32 cnt = driver->getDynamicLightCount();

			// Load the inverse world matrix.
			core::matrix4 invWorldMat;
			driver->getTransform(video::ETS_WORLD).getInverse(invWorldMat);

			for (u32 i=0; i<2; ++i)
			{
				video::SLight light;

				if (i<cnt)
					light = driver->getDynamicLight(i);
				else
				{
					light.DiffuseColor.set(0,0,0); // make light dark
					light.Radius = 1.0f;
				}

				light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation

				// Transform the light by the inverse world matrix to get it into object space.
				invWorldMat.transformVect(light.Position);

				services->setVertexShaderConstant(
					reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);

				services->setVertexShaderConstant(
					reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
			}

			// Obtain the view position by transforming 0,0,0 by the inverse view matrix
			// and then multiply this by the inverse world matrix.
			core::vector3df viewPos(0.0f, 0.0f, 0.0f);
			core::matrix4 inverseView;
			driver->getTransform(video::ETS_VIEW).getInverse(inverseView);
			inverseView.transformVect(viewPos);
			invWorldMat.transformVect(viewPos);
			services->setVertexShaderConstant(reinterpret_cast<const f32*>(&viewPos.X), 16, 1);

			// set scale factor
			f32 factor = 0.02f; // default value
			if (DestCurrentScale != 0.0f)
				factor = DestCurrentScale;

			f32 c6[] = {factor, factor, factor, factor};
			services->setPixelShaderConstant(c6, 0, 1);
		}
	};
#endif

//! Class for rendering normal maps with OpenGL
#ifdef DELPHI_WRAP
class COpenGLParallaxMapRenderer : public COpenGLShaderMaterialRenderer
#else
class COpenGLParallaxMapRenderer : public COpenGLShaderMaterialRenderer, public IShaderConstantSetCallBack
#endif
{
public:

	//! Constructor
	COpenGLParallaxMapRenderer(video::COpenGLDriver* driver,
		s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial);

	//! Destructor
	~COpenGLParallaxMapRenderer();

	//! Called by the engine when the vertex and/or pixel shader constants for an
	//! material renderer should be set.
#ifdef DELPHI_WRAP
#else
	virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData);
#endif

	//! Returns the render capability of the material.
	virtual s32 _STDCALL_ getRenderCapability() const;

#ifdef DELPHI_WRAP
#else
	virtual void OnSetMaterial(const SMaterial& material) { }
#endif
	virtual void _STDCALL_ OnSetMaterial(const video::SMaterial& material,
		const video::SMaterial& lastMaterial,
		bool resetAllRenderstates, video::IMaterialRendererServices* services);

protected:

	bool CompiledShaders;
	f32 CurrentScale;
};


} // end namespace video
} // end namespace irr

#endif
#endif

